package com.cw.utils.java.sm;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.crypto.digest.SM3;
import cn.hutool.crypto.symmetric.SM4;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 陈伟
 * @Date: 2021/09/28 11:07
 * @Description:国密介绍：
 * SM2为基于椭圆曲线密码的公钥密码算法标准，包含数字签名、密钥交换和公钥加密，用于替换RSA / Diffie-Hellman / ECDSA / ECDH 等国际算法。
 * SM3为密码哈希算法，用于替代MD5 / SHA-s1 / SHA-256等国际算法。
 * SM4为分组密码，用于替代DES / AES等国际算法。

 * @Version s1.0
 **/
public class SltasSMUtil {
    private static Logger log = LoggerFactory.getLogger(SltasSMUtil.class);

    public static volatile String DEFAULT_SM3_KEY = "adda56sdgbnjh234";

    public static volatile String DEFAULT_SM4_KEY = "044CB5LiL6L295bm";



  /*
   * @Author 陈伟
   * @Date 2021/10/13 18:59
   * @description 创建 SM2 公私钥对
    * @param:
   * @Return java.util.Map<java.lang.String,java.lang.String>
    * publicKey,privateKey
   */
    public static Map<String, String> createSM2Key() {
        Map<String, String> sm2Key = new HashMap<>();
        SM2 sm2 = new SM2();
        String publicKey = sm2.getPublicKeyBase64();
        System.out.println("公钥(前端js使用)：" + Hex.toHexString(sm2.getQ(false)));
        
        String privateKey = sm2.getPrivateKeyBase64();
        System.out.println("公钥：" +publicKey);
        System.out.println("私钥：" +privateKey);
        log.info("公钥：{}" ,publicKey);
        log.info("私钥：{}" ,privateKey);
        sm2Key.put("publicKey",publicKey);
        sm2Key.put("privateKey",privateKey);
        return sm2Key;
    }


    /**
     * 自定义公私钥，SM2 公钥加密
     *
     * @param publicKey
     * @param plainText
     */

    public static String sm2Encrypt(String publicKey, String plainText) {
        SM2 sm2 = new SM2(null, publicKey);
        String ciphertext = sm2.encryptBase64(plainText, KeyType.PublicKey);
        return ciphertext;
    }

    /**
     *  自定义公私钥，SM2 私钥解密
     *
     * @param privateKey
     * @param ciphertext
     */
    public static String sm2Decrypt(String privateKey, String ciphertext) {
        SM2 sm2 = new SM2(privateKey, null);
        String plainText = sm2.decryptStr(ciphertext, KeyType.PrivateKey);
        return plainText;
    }
    /**
     * SM2 私钥解密
     *
     * @param privateKey
     * @param ciphertextFormJs
     */
    public static String sm2DecryptForJs(String privateKey, String ciphertextFormJs) {
        SM2 sm2 = new SM2(privateKey, null);
        byte[] decode = Hex.decode(ciphertextFormJs);
		byte[] decrypt = sm2.decrypt(decode, KeyType.PrivateKey);
		String plainText = new String(java.util.Base64.getDecoder().decode(decrypt), StandardCharsets.UTF_8);
        return plainText;
    }

    /*
     * @Author 陈伟
     * @Date 2021/10/12 17:38
     * @description 通过私钥进行文件签名
      * @param: privateKey
     * @param: plainText
     * @Return java.lang.String
     */
    public static String signSm2PrivateKey(String privateKey, String plainText) {
        String signature = "";
        if (StringUtils.isEmpty(privateKey) || null == plainText) {
            log.error("缺少必要参数!");
            throw new RuntimeException("缺少必要参数!");
        } else {
            long startTime = System.currentTimeMillis();
            String signs = "";
            try {
                SM2 sm2 = new SM2(privateKey, null);
                //这里需要手动设置，sm2 对象的默认值与我们期望的不一致 , 使用明文编码
                sm2.usePlainEncoding();
                sm2.setMode(SM2Engine.Mode.C1C2C3);
                byte[] sign = sm2.sign(plainText.getBytes(StandardCharsets.UTF_8), null);
                //change encoding : hex to base64
                signs = Base64.encode(sign);
                signature = signs;
            } catch (Exception e) {
                log.error("签名失败",e);
                throw new RuntimeException("签名失败," + e.getMessage());
            }
            long endTime = System.currentTimeMillis();
            //log.info("本次签名操作,所得签名为:" + signs + ",所耗时间为：" + (endTime - startTime));
        }
        return signature;
    }


    /*
     * @Author 陈伟
     * @Date 2021/10/12 17:40
     * @description 通过公钥进行文件验签
      * @param: publicKey
     * @param: sign 签名（原先为hex处理后的16位，现在改为base处理后的64位）
     * @param: dataBytes
     * @Return java.lang.Boolean
     */
    public static Boolean verifySignByPublicKey(String publicKey, String sign, String plainText) {
        Boolean verify = false;
        if (StringUtils.isEmpty(publicKey) || StringUtils.isEmpty(sign) || null == plainText) {
            throw new RuntimeException("缺少必要参数!");
        } else {
            long startTime = System.currentTimeMillis();
            try {
                SM2 sm2 = new SM2(null, publicKey);
                sm2.usePlainEncoding();
                sm2.setMode(SM2Engine.Mode.C1C2C3);
                verify = sm2.verify(plainText.getBytes(StandardCharsets.UTF_8), Base64.decode(sign));
            } catch (Exception e) {
            	log.error("验签失败",e);
                throw new RuntimeException("验签失败," + e.getMessage());
            }
            long endTime = System.currentTimeMillis();
            //log.info("本次验签操作,所得结果为:" + verify + ",所耗时间为：" + (endTime - startTime));
        }
        return verify;
    }
    /*
     * @Author 陈伟
     * @Date 2021/9/28 15:05
     * @description 默认加盐
      * @param: content
     * @Return java.lang.String
     */
    public static String sm3DigestHex(String content){
        SM3 sm3 = new SM3(DEFAULT_SM3_KEY.getBytes(StandardCharsets.UTF_8));
        return sm3.digestHex(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 15:05
     * @description 指定加盐
      * @param: content
     * @param: key
     * @Return java.lang.String
     */
    public static String sm3DigestHex(String content, String key){
        SM3 sm3 = new SM3(key.getBytes(StandardCharsets.UTF_8));
        return sm3.digestHex(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:26
     * @description 根据默认密钥，生成16进制的密文串
      * @param: content
     * @Return java.lang.String
     */
    public static String sm4EncryptHex(String content){
        SM4 sm4 = new SM4(DEFAULT_SM4_KEY.getBytes(StandardCharsets.UTF_8));
        return sm4.encryptHex(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:26
     * @description 根据默认密钥，生成Base64格式的密文串
      * @param: content
     * @Return java.lang.String
     */
    public static String sm4EncryptBase64(String content){
        SM4 sm4 = new SM4(DEFAULT_SM4_KEY.getBytes(StandardCharsets.UTF_8));
        return sm4.encryptBase64(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:27
     * @description 指定密钥，生成16进制的密文串
      * @param: content
     * @param: key 长度必须为16
     * @Return java.lang.String
     */
    public static String sm4EncryptHex(String content, String key){
        if(key==null || key.length()!=16){
            log.error("key的长度必须为16");
            return null;
        }
        SM4 sm4 = new SM4(key.getBytes(StandardCharsets.UTF_8));
        return sm4.encryptHex(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:28
     * @description 指定密钥，生成Base64格式的密文串
      * @param: content
     * @param: key 长度必须为16
     * @Return java.lang.String
     */
    public static String sm4EncryptBase64(String content, String key){
        if(key==null || key.length()!=16){
            log.error("key的长度必须为16");
            return null;
        }
        SM4 sm4 = new SM4(key.getBytes(StandardCharsets.UTF_8));
        return sm4.encryptBase64(content);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:28
     * @description 根据默认密钥，进行解密
      * @param: encryptContent
     * @Return java.lang.String
     */
    public static String sm4DecryptStr(String encryptContent){
        SM4 sm4 = new SM4(DEFAULT_SM4_KEY.getBytes(StandardCharsets.UTF_8));
        return sm4.decryptStr(encryptContent, CharsetUtil.CHARSET_UTF_8);
    }

    /*
     * @Author 陈伟
     * @Date 2021/9/28 14:28
     * @description 指定密钥，进行解密
      * @param: encryptContent
     * @param: key 长度必须为16
     * @Return java.lang.String
     */
    public static String sm4DecryptStr(String encryptContent, String key){
        if(key==null || key.length()!=16){
            log.error("key的长度必须为16");
            return null;
        }
        SM4 sm4 = new SM4(key.getBytes(StandardCharsets.UTF_8));
        return sm4.decryptStr(encryptContent, CharsetUtil.CHARSET_UTF_8);
    }


//    public static void main(String[] args) {
//        String e = SltasSMUtil.sm4EncryptBase64("sltfGyHk75H7hHR39G7Gy");
//        System.out.println(e);
//
//        String e2 = SltasSMUtil.sm4EncryptBase64("sl$%123456","1234554321123456");
//        System.out.println(e2);
//
//        String d = SltasSMUtil.sm4DecryptStr("Empjzi1MUThJd3ZZiOy8Ew==");
//        System.out.println(d);
//
//        String d2 = SltasSMUtil.sm4DecryptStr("vvic/v80t7EAgnfQw0hJXg==");
//        System.out.println(d2);
//
//        String d3 = SltasSMUtil.sm4DecryptStr("ohqPNuio51pNS94rl3gS0u0vufRrhzqQg/b8xbWQQYA=");
//        System.out.println(d3);
//
//        String d4 = SltasSMUtil.sm4DecryptStr("/JvJfTW145yzVTslvr1J7Q==");
//        System.out.println(d4);
//
//        String d5 = SltasSMUtil.sm4DecryptStr("YbDCJtSVYdx9ZckKl0rBOQ==");
//        System.out.println(d5);
//
//        String d6 = SltasSMUtil.sm4DecryptStr("Empjzi1MUThJd3ZZiOy8Ew==");
//        System.out.println(d6);
//    }

//    public static void main(String[] args) {
//        System.out.println(SltasSMUtil.sm3DigestHex("123456"));
//        System.out.println(SltasSMUtil.sm3DigestHex("123456","aabbccdd"));
//    }

//    public static void main(String[] args) {
//    	createSM2Key();
//        
//    }
//    public static void main(String[] args) {
//        String privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgXvCy40dLdzlGHkRSGPewU2xVMOfEIS30QkjNlhizZAugCgYIKoEcz1UBgi2hRANCAATlW8w8aYUvyeQiOk+hgzfIsi9K708gI8d17W3K6VARyJtZ3f8bUVxDZUZDbfhMCTvvKVRQuJrrhxrB8eGJ/pNd";
//        String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5VvMPGmFL8nkIjpPoYM3yLIvSu9PICPHde1tyulQEcibWd3/G1FcQ2VGQ234TAk77ylUULia64cawfHhif6TXQ==";
//        String plainText = "abc123";
//        String jiami = SltasSMUtil.sm2Encrypt(publicKey,plainText);
//        //BLe44z7Dv2q2m9sqrQQZfTjJvUXdO3+bigP2P9QBLe6JyjprR95zyNDiZ3bDAzDBsRxW0eWugHwOB1Z3j5nm/8aNqaZqU2Nwnqah37iE0Und4AylbXvmK36qfKZHVBiyfOehjy7qNQ==
//        System.out.println(jiami);
//
//        System.out.println(SltasSMUtil.sm2Decrypt(privateKey,jiami));
//    }


//    public static void main(String[] args) {
//        String privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgXvCy40dLdzlGHkRSGPewU2xVMOfEIS30QkjNlhizZAugCgYIKoEcz1UBgi2hRANCAATlW8w8aYUvyeQiOk+hgzfIsi9K708gI8d17W3K6VARyJtZ3f8bUVxDZUZDbfhMCTvvKVRQuJrrhxrB8eGJ/pNd";
//        String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5VvMPGmFL8nkIjpPoYM3yLIvSu9PICPHde1tyulQEcibWd3/G1FcQ2VGQ234TAk77ylUULia64cawfHhif6TXQ==";
//        String plainText = "abc123";
//        String sign = SltasSMUtil.signSm2PrivateKey(privateKey,plainText);
//        //XOxeqxwnLKJO+oRtocUslnJkD/2XtT7V+ZCYgLbmy8AzLDR8cPTwrc7N8q6M4RrqCSwEq+VxJSVYwsxB60MZBA==
//        System.out.println(sign);
//
//        System.out.println(SltasSMUtil.verifySignByPublicKey(publicKey,sign,plainText));
//    }
    
}